﻿namespace Rialternative.DescriptionProvider
{
    using System;
    using System.Globalization;
    using System.ServiceModel.DomainServices.Server;
    using Rialternative.DomainService;

    /// <summary>
    /// EntityDomainServiceDescriptionProviderAttribute : attribut to use on a DomainService
    /// A DomainService must implement IEntityDomainService :
    /// - explicitly
    /// - Or with the "Ignore" attribut on each method
    /// To avoid these methods from being exposed to the client.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    public sealed class EntityDomainServiceDescriptionProviderAttribute : DomainServiceDescriptionProviderAttribute
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="EntityDomainServiceDescriptionProviderAttribute"/> class.
        /// </summary>
        /// <param name="objectContextType">Type of the object context.</param>
        public EntityDomainServiceDescriptionProviderAttribute(Type objectContextType)
            : base(typeof(EntityDomainServiceDescriptionProvider))
        {
            this.ObjectContextType = objectContextType;
        }

        /// <summary>
        /// Gets the type of the object context.
        /// </summary>
        /// <value>The type of the object context.</value>
        public Type ObjectContextType { get; private set; }

        /// <summary>
        /// This method creates an instance of the <see cref="T:System.ServiceModel.DomainServices.Server.DomainServiceDescriptionProvider"/>. Subclasses can override this.
        /// method to provide their own construction logic.
        /// </summary>
        /// <param name="domainServiceType">The <see cref="T:System.ServiceModel.DomainServices.Server.DomainService"/> type to create a description provider for.</param>
        /// <param name="parent">The parent description provider. May be null.</param>
        /// <returns>The description provider.</returns>
        public override DomainServiceDescriptionProvider CreateProvider(Type domainServiceType, DomainServiceDescriptionProvider parent)
        {
            if (domainServiceType == null)
            {
                throw new ArgumentNullException("domainServiceType");
            }

            if (!typeof(RepositoryDomainService).IsAssignableFrom(domainServiceType))
            {
                throw new ArgumentException(
                    String.Format(
                            CultureInfo.InvariantCulture,
                            "Service '{0}' must derive from '{1}",
                            domainServiceType.Name,
                            typeof(RepositoryDomainService).Name),
                    "domainServiceType");
            }

            return new EntityDomainServiceDescriptionProvider(domainServiceType, parent, this.ObjectContextType);
        }
    }
}
